原文戳我
JLL是DLL(Dynamic-Link Library)的双关语, J for Julia
JLL包的内部结构实际上并不复杂, 一个典型的JLL结构:
LICENSE,README.md,*.toml是常规文件, 略;
src/NAME_jll.jl是软件包的主要入口, 在输入using NAME_jll时执行;
src/wrappers/目录记录支持的不同平台;
src/wrappers是自动生成的包装器, 加载当前JLL的依赖JLL, 并到处生成当前JLL的build_tarballs.jl所列出的产品名, 同时还定义以下不导出的变量:
artifact_dir: 当前二进制文件的安装目录(绝对路径);
PATH: 执行当前JLL所需要的PATH环境(如果需要的话);
PATH_list: 以向量形式存储的PATH中的目录Vector{String};
LIBPATH: 搜索依赖库的PATH;
LIBPATH_list: 依赖库PATH的Vector;
每个包装文件还定义了__init__()功能, 设置每次加载包时执行的代码;
LibraryProduct <: Product类型表示共享库, 可以用ccall调用, 假设一个名为libdataproc的jll, 包装器会定义如下变量:
常量libdataproc, 可以被ccall调用: num_chars = ccall((:count_characters, libdataproc), Cint, (Cstring, Cint), data_lines[1], length(data_lines[1]))
libdataproc_path: 共享库的绝对路径, 不是常量, 所以不能被ccall调用;
libdataproc_handle: 共享库在内存中的地址;
ExecutableProduct <: Product类型是在当前平台上可运行的二进制文件, 假设一个名为mungify_exe的可执行文件, 可以在包装器中以如下两种方式调用:
以插值的形式直接运行函数, 虽然代码不太易读, 但是是线程安全的, 所以首推这种方式:
用do...end代码块包裹, 分配函数名, 再插值调用, 更清晰:
FileProduct <: Product对应简单文件, 记录文件的绝对路径:
JLL利用Artifacts来工作, 可以用Overrides.toml来配置用自己的可执行文件/库/文件来覆盖JLL, 根据包是否被dev, 可以分三种覆盖方式。